package com.kuaiyin.executor;

import com.kuaiyin.entity.TestPlan;
import com.kuaiyin.service.ITestPlanService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import com.kuaiyin.enums.Status;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * Quartz 管理类：负责添加/更新/删除定时任务
 */
@Component
@Slf4j
public class QuartzManager {

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private ApplicationContext applicationContext;

    private ITestPlanService testPlanService;

    @PostConstruct
    public void init() {
        // 延迟获取 Bean，避免与 TestPlanServiceImpl 形成循环依赖
        testPlanService = applicationContext.getBean(ITestPlanService.class);

        List<TestPlan> plans = testPlanService.listByScheduleConfigNotNull();
        for (TestPlan plan : plans) {
            if (plan.getStatus() == Status.FROZEN &&
                    plan.getScheduleConfig() != null &&
                    !plan.getScheduleConfig().isEmpty()) {
                addJob(plan.getId(), plan.getScheduleConfig());
            }
        }
    }

    /**
     * 添加一个定时任务
     */
    public void addJob(Long planId, String cronExpression) {
        try {
            JobDetail jobDetail = buildJobDetail(planId);
            Trigger trigger = buildTrigger(planId, cronExpression);

            scheduler.scheduleJob(jobDetail, trigger);
            log.info("已添加定时任务: planId={}", planId);
        } catch (Exception e) {
            log.error("添加定时任务失败 planId={}", planId, e);
        }
    }

    /**
     * 更新一个定时任务
     */
    /**
     * 更新一个定时任务 (方法一：推荐)
     */
    public void updateJob(Long planId, String cronExpression) {
        try {
            if (!CronExpression.isValidExpression(cronExpression)) {
                throw new IllegalArgumentException("无效的 Cron 表达式: " + cronExpression);
            }

            TriggerKey triggerKey = TriggerKey.triggerKey("test_plan_" + planId, "test_plan_group");
            JobKey jobKey = JobKey.jobKey("test_plan_" + planId, "test_plan_group");

            // 1. 检查 Job 是否存在，不存在则添加
            if (!scheduler.checkExists(jobKey)) {
                scheduler.addJob(buildJobDetail(planId), true, true);
            }

            // 2. 如果已有触发器存在，则先删除
            if (scheduler.checkExists(triggerKey)) {
                scheduler.pauseTrigger(triggerKey);         // 暂停触发器
                scheduler.unscheduleJob(triggerKey);       // 移除触发器
            }

            // 3. 构建新触发器并绑定到已有 Job
            CronTrigger newTrigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                    .forJob(jobKey)
                    .build();

            scheduler.scheduleJob(newTrigger);  // 重新绑定触发器

            // 4. 恢复 Job 的执行（如果之前被暂停）
            scheduler.resumeJob(jobKey);

            log.info("已更新定时任务并应用新的 cron 表达式: planId={}", planId);
        } catch (Exception e) {
            log.error("更新定时任务失败 planId={}", planId, e);
        }
    }


    /**
     * 删除一个定时任务
     */
    public void deleteJob(Long planId) {
        try {
            JobKey jobKey = JobKey.jobKey("test_plan_" + planId, "test_plan_group");
            scheduler.deleteJob(jobKey);
            log.info("已删除定时任务: planId={}", planId);
        } catch (Exception e) {
            log.error("删除定时任务失败 planId={}", planId, e);
        }
    }

    private JobDetail buildJobDetail(Long planId) {
        return JobBuilder.newJob(TestPlanQuartzJob.class)
                .withIdentity("test_plan_" + planId, "test_plan_group")
                .storeDurably()
                .usingJobData(TestPlanQuartzJob.PLAN_ID, planId)
                .build();
    }

    private Trigger buildTrigger(Long planId, String cronExpression) {
        return TriggerBuilder.newTrigger()
                .withIdentity("test_plan_" + planId, "test_plan_group")
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                .build();
    }
}
